package com.jfinal.complex.tablesplit.abst;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.jfinal.complex.exception.TableSplitException;
import com.jfinal.complex.tablesplit.interfaces.ITableSplitConverter;
import com.jfinal.complex.tablesplit.interfaces.ITableSplitFactory;
import com.jfinal.complex.tablesplit.model.CrossVar;
import com.jfinal.complex.tablesplit.model.interfaces.ITableSplitCfg;
import com.jfinal.complex.tablesplit.model.interfaces.ITableSplitMappingCfg;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Logger;
/**
 * 
 * @author  约黄昏 yuehhfeng@foxmail.com
 *
 */
public abstract class AbstractTableSplitFactory implements ITableSplitFactory {
	private static Logger log = Logger.getLogger(AbstractTableSplitFactory.class);
	private boolean isUseCache = true;
	
	@Override
	public String createQuerySQL(String sql, Map<String, Object> attrs) {
		String[] tmpTableName = getParamFromString(sql, "{", "}");

		if ((tmpTableName == null) || (tmpTableName.length == 0)) {
			return sql;
		}

		if (attrs == null) {
			throw new TableSplitException("attrs 参数不应该为null");
		}

		List<CrossVar> crossList = new ArrayList<CrossVar>();

		CrossVar var = null;
		for (int i = 0; i < tmpTableName.length; i++) {
			String tableName = tmpTableName[i];

			ITableSplitCfg tableSplit = getTableSplit(tableName);
			if (tableSplit == null) {
				throw new TableSplitException("找不到表名为"+tableName+"的分表配置！");
			}

			List<ITableSplitMappingCfg> mappingList = this
					.getTableSplitMapping(tableName);
			if (mappingList == null || mappingList.size() == 0) {
				throw new TableSplitException("找不到表名为"+tableName+"的分表转换规则配置！");
			}

			var = new CrossVar();
			var.setTableName(tableName);
			try {
				for (ITableSplitMappingCfg mapping : mappingList) {
					Class<?> clazz = Class.forName(mapping
							.getColumnConvertClass());
					ITableSplitConverter converter = (ITableSplitConverter) clazz
							.newInstance();

					String column = mapping.getColumnName();
					if (StrKit.isBlank(column)) {
						throw new Exception(tableName + "分表转换规则配置column值为空");
					}
					Object object = attrs.get(column);
					if (object == null) {
						throw new Exception("Map attr中找不到" + column + "的值");
					}
					String value = converter.convert(object);

					var.addColAndValue(column, value);
				}
			} catch (Exception e) {
				throw new TableSplitException(e.getMessage(),e);
			}

			crossList.add(var);
		}

		sql = cross(sql, crossList);
		return sql;
	}

	@Override
	public String createTableName(String oldTableName, Map<String, Object> attrs) {
		// TODO Auto-generated method stub
		String[] tmpTableName = getParamFromString(oldTableName,
				"{", "}");

		if ((tmpTableName == null) || (tmpTableName.length == 0)) {
			return oldTableName;
		}
		if (tmpTableName.length != 1) {
			throw new TableSplitException("不正确的表名表达式:" + oldTableName);
		}

		if (attrs == null) {
			throw new TableSplitException("attrs 参数不应该为null");
		}
		
		String tableName = tmpTableName[0];

		if (log.isDebugEnabled()) {
			log.debug("转换表名:" + tableName);

			StringBuffer sb = new StringBuffer();
			Set<String> nameSet = attrs.keySet();
			Iterator<String> it = nameSet.iterator();
			while (it.hasNext()) {
				String name = it.next();
				sb.append("[" + name + " = " + attrs.get(name) + "]  ");
			}
			log.debug("Map attr的值:" + sb.toString());
		}
		ITableSplitCfg tableSplit = getTableSplit(tableName);
		if (tableSplit == null) {
			throw new TableSplitException("找不到表名为"+tableName+"的分表配置！");
		}

		List<ITableSplitMappingCfg> mappingList = this
				.getTableSplitMapping(tableName);
		if (mappingList == null || mappingList.size() == 0) {
			throw new TableSplitException("找不到表名为"+tableName+"的分表转换规则配置！");
		}

		CrossVar var = new CrossVar();
		var.setTableName(tableName);
		try {
			for (ITableSplitMappingCfg mapping : mappingList) {
				Class<?> clazz = Class.forName(mapping.getColumnConvertClass());
				ITableSplitConverter converter = (ITableSplitConverter) clazz
						.newInstance();

				String column = mapping.getColumnName();
				if (StrKit.isBlank(column)) {
					throw new Exception(tableName + "分表转换规则配置column值为空");
				}
				Object object = attrs.get(column);
				if (object == null) {
					throw new Exception("Map attr中找不到" + column + "的值");
				}
				String value = converter.convert(object);

				var.addColAndValue(column, value);
			}
		} catch (Exception e) {
			throw new TableSplitException(e.getMessage(),e);
		}

		String newTableName = getTableNameByCrossVar(var);
		return newTableName;
	}

	/**
	 * 通过查询是表名是否有分表配置，有则是分表
	 */
	public boolean isTableSplit(String tableName) {
		ITableSplitCfg tableSplit = getTableSplit(tableName);

		if (tableSplit != null) {
			return true;
		}
		return false;
	}
	
	/**
	 * 取分表规则
	 * 
	 * @param tableName
	 * @return
	 */
	public abstract ITableSplitCfg getTableSplit(String tableName);

	/**
	 * 取分表规则转换实现类
	 * 
	 * @param tableName
	 * @return
	 */
	public abstract List<ITableSplitMappingCfg> getTableSplitMapping(
			String tableName);


	public boolean isUseCache() {
		return isUseCache;
	}

	public ITableSplitFactory setUseCache(boolean isUseCache) {
		this.isUseCache = isUseCache;
		return this;
	}

	private String getTableNameByCrossVar(CrossVar var) {
		ITableSplitCfg tableSplit = getTableSplit(var.getTableName());
		if (tableSplit == null) {
			throw new TableSplitException("找不到表名为"+var.getTableName()+"的分表配置！");
		}

		String expr = tableSplit.getTableNameExpr();

		expr = expr.replace("T[TABLE_NAME]", var.getTableName());
		HashMap<String, String> map = var.getColsAndValues();
		Set<String> cols = map.keySet();
		for (Iterator<String> iter = cols.iterator(); iter.hasNext();) {
			String item = (String) iter.next();
			expr = expr.replace("C[" + item + "]", map.get(item));
		}

		return expr;
	}

	private String cross(String sql, List<CrossVar> list) {
		for (CrossVar var : list) {
			String tableName = getTableNameByCrossVar(var);
			sql = sql.replace("{" + var.getTableName() + "}", tableName);
		}
		return sql;
	}
	
	private String[] getParamFromString(String aSourceString,
			String aStartStr, String aEndStr) {
		aSourceString = aSourceString + aEndStr;
		String strSource = aSourceString;
		ArrayList<String> strKey = new ArrayList<String>();
		int iStartIndex = strSource.indexOf(aStartStr);
		int iStartLength = aStartStr.length();
		int iEndLength = aEndStr.length();
		String strTemp = "";
		strTemp = strSource.substring(iStartIndex + iStartLength,
				strSource.length());
		int iEndIndex = strTemp.indexOf(aEndStr)
				+ strSource.substring(0, iStartIndex + iStartLength).length();
		if (iEndIndex == iStartIndex) {
			strKey.add(strTemp);
		}
		while ((iStartIndex != -1) && (iEndIndex != -1)
				&& (iStartIndex < iEndIndex)) {
			strTemp = strSource
					.substring(iStartIndex + iStartLength, iEndIndex);
			strKey.add(strTemp);
			strSource = strSource.substring(iEndIndex + iEndLength,
					strSource.length());
			iStartIndex = strSource.indexOf(aStartStr);
			strTemp = strSource.substring(iStartIndex + iStartLength,
					strSource.length());
			iEndIndex = strTemp.indexOf(aEndStr)
					+ strSource.substring(0, iStartIndex + iStartLength)
							.length();
		}
		return ((String[]) strKey.toArray(new String[0]));
	}
}
